﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LightCAD.Three.OpenGL;

namespace LightCAD.Three
{

    public class WebGLObjects : IDispose
    {
        public readonly WebGLGeometries geometries;
        public readonly WebGLAttributes attributes;
        public readonly WebGLInfo info;
        public JsObj<BufferGeometry, int?> updateMap;
        public WebGLObjects(WebGLGeometries geometries, WebGLAttributes attributes, WebGLInfo info)
        {
            this.geometries = geometries;
            this.attributes = attributes;
            this.info = info;
            this.updateMap = new JsObj<BufferGeometry, int?>();
        }
        public BufferGeometry update(Object3D _object)
        {

            var frame = info.render.frame;

            var geometry = (_object is IGeometry) ? (_object as IGeometry).getGeometry() : null;
            var buffergeometry = geometries.get(_object, geometry);

            // Update once per frame
            var preFrame = updateMap.get(buffergeometry);
            if (preFrame != frame)
            {
                geometries.update(buffergeometry);
                updateMap.set(buffergeometry, frame);
                if (preFrame == null)
                    buffergeometry.addEventListener("dispose", onGeometryDispose);
            }

            if (_object is InstancedMesh)
            {

                if (_object.hasEventListener("dispose", onInstancedMeshDispose) == false)
                {

                    _object.addEventListener("dispose", onInstancedMeshDispose);

                }
                var instanceMesh = _object as InstancedMesh;
                attributes.update(instanceMesh.instanceMatrix, gl.ARRAY_BUFFER);

                if (instanceMesh.instanceColor != null)
                {

                    attributes.update(instanceMesh.instanceColor, gl.ARRAY_BUFFER);
                }
            }

            return buffergeometry;

        }
        public void onGeometryDispose(EventArgs e)
        {
            var geometry = e.target as BufferGeometry;
            geometry.removeEventListener("dispose", onGeometryDispose);
            this.remove(geometry);
        }
        //by rider
        public void remove(BufferGeometry buffergeometry)
        {

            if (updateMap.has(buffergeometry))
            {
                updateMap.remove(buffergeometry);
            }
        }

        public void dispose()
        {
            updateMap.Clear();
            updateMap = new JsObj<BufferGeometry, int?>();

        }

        public void onInstancedMeshDispose(EventArgs e)
        {

            var instancedMesh = (InstancedMesh)e.target;

            instancedMesh.removeEventListener("dispose", onInstancedMeshDispose);

            attributes.remove(instancedMesh.instanceMatrix);

            if (instancedMesh.instanceColor != null) attributes.remove(instancedMesh.instanceColor);

        }
    }
}
